﻿using JetBrains.Annotations;
using MultiLang;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
using Rsdn.Janus.ObjectModel;
using Rsdn.SmartApp;

namespace Rsdn.Janus
{
    internal class UIShell : IUIShell
    {
        private readonly Func<IWin32Window> _parentWindowGetter;
		private readonly Action<bool> _uiFreezer;
        private readonly AsyncOperation _ctorAsyncOperation;
        private readonly HashSet<UIFreezer> _freezers = new HashSet<UIFreezer>();
        private readonly SynchronizationContext _uiSyncContext = SynchronizationContext.Current;
        HashSet<Control> updateControls = new HashSet<Control>();
        private ListView activeGrid;
        private object _activeFeatureView;

        /// <exception cref="ArgumentNullException"><paramref name="parentWindowGetter" /> is <c>null</c>.</exception>
		public UIShell(Func<IWin32Window> parentWindowGetter, [NotNull] Action<bool> uiFreezer)
        {
			if (parentWindowGetter == null)
                throw new ArgumentNullException("parentWindowGetter"); //MLHIDE
			if (uiFreezer == null) throw new ArgumentNullException("uiFreezer");
            _parentWindowGetter = parentWindowGetter;
			_uiFreezer = uiFreezer;
            _ctorAsyncOperation = AsyncHelper.CreateOperation();
        }

        #region IUIShell Members
        /// <summary>
        /// Создать <see cref="AsyncOperation"/>, привязанную к UI потоку.
        /// </summary>
        /// <exception cref="ApplicationException">Error creating async operation.</exception>
        public AsyncOperation CreateUIAsyncOperation()
        {
            AsyncOperation asyncOp = null;
            _ctorAsyncOperation.Send(() => asyncOp = AsyncHelper.CreateOperation());
            if (asyncOp == null)
            {
                throw new ApplicationException(ml.ml_string(385, "Ошибка создания асинхронной операции."));
            }
            return asyncOp;
        }

        public SynchronizationContext UISyncContext
        {
            get { return _uiSyncContext; }
        }

        /// <summary>
        /// Получить главного родителя окон.
        /// </summary>
        public IWin32Window GetMainWindowParent()
        {
            return _parentWindowGetter();
        }

        /// <summary>
        /// Заморозить UI приложения.
        /// </summary>
        public IDisposable FreezeUI(IServiceProvider provider)
        {
            lock (_freezers)
            {
                if (_freezers.Count == 0)
                {
					_ctorAsyncOperation.Post(
						() =>
						{
							_uiFreezer(false);
							var notifyIconSvc = provider.GetService<INotifyIconService>();
							if (notifyIconSvc != null)
								notifyIconSvc.Enabled = false;
						}
					);
				}
				var freezer = new UIFreezer(
					f =>
					{
						lock (_freezers)
						{
							_freezers.Remove(f);
							if (_freezers.Count == 0)
							{
								_ctorAsyncOperation.Post(
									() =>
										{
											_uiFreezer(true);
										var notifyIconSvc = provider.GetService<INotifyIconService>();
										if (notifyIconSvc != null)
											notifyIconSvc.Enabled = true;
									}
								);
							}
						}
					});
				_freezers.Add(freezer);
				return freezer;
			}
		}

        /// <summary>
        /// Добавляет контрол/окно для обновления визуальной информации.
        /// </summary>
        /// <param name="control">The control.</param>
        public void AddRefreshControl(Control control)
        {
            if (!updateControls.Contains(control))
            {
                updateControls.Add(control);
            }
        }

        /// <summary>
        /// Удаляет контрол/окно для обновления визуальной информации.
        /// </summary>
        /// <param name="control">The control.</param>
        public void RemoveRefreshControl(Control control)
        {
            if (updateControls.Contains(control))
            {
                updateControls.Remove(control);
            }
        }

        /// <summary>
        /// Обновляет данные, связанные с UI.
        /// </summary>
        /// <param name="serviceProvider">The service provider.</param>
        public void RefreshData(IServiceProvider serviceProvider)
        {
#if FRM_UPDATE_TRACE
            Trace.WriteLine("FRU: UIShell.RefreshData");              //MLHIDE
#endif
            //IIncomingFolderUpdate folderUpdate = (IIncomingFolderUpdate)serviceProvider.GetService(typeof(IIncomingFolderUpdate));
            //IEnumerable<Feature> updates = folderUpdate.GetUpdates;

            //IFeature activeFeature = ObjectModel.Features.Instance.ActiveFeature;
            //if (activeFeature != null)
            //{
            //    activeFeature.Refresh(); 
            //}

            //foreach (Feature feature in updates)
            //{
            //    feature.Refresh();
            //}

            Features.Instance.Refresh(); // Note*** reread all forums data here

            if (ApplicationManager.Instance != null)
            {

                ApplicationManager.Instance.Navigator.RefreshDataViews();
            }

            Features.Instance.RefreshSelection();
        }

        /// <summary>
        /// Обновляет заранее установленный список окон.
        /// </summary>
        public void RefreshUI()
        {
            // TODO how about frezee?
            foreach (Control control in updateControls)
            {
                //control.Update();
                control.Invalidate();
            }
        }


        /// <summary>
        /// Получить или устновить активный грид контрол.
        /// примечание: Грид контрол наследован от ListView
        /// </summary>
        /// <value>Активный грид контрол.</value>
        public ListView ActiveGrid
        {
            get { return activeGrid; }
            set { activeGrid = value; }
        }


        public object ActiveFeatureView
        {
            get { return _activeFeatureView; }
            set { _activeFeatureView = value; }
        }

        /// <summary>
        /// Очистить активный список сообщений
        /// </summary>
        public void ClearActiveFeatureView()
        {
            IFeatureView featureViev = _activeFeatureView as IFeatureView;
            if (featureViev != null)
            {
                featureViev.Clear();
            }
        }

        #endregion

        #region UIFreezer class
        private class UIFreezer : IDisposable
        {
            private readonly Action<UIFreezer> _unfreezeHandler;
            private bool _disposed;

            public UIFreezer(Action<UIFreezer> unfreezeHandler)
            {
                _unfreezeHandler = unfreezeHandler;
            }

            #region IDisposable Members
            ///<summary>
            ///Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
            ///</summary>
            public void Dispose()
            {
                if (_disposed)
                    return;
                _unfreezeHandler(this);
                _disposed = true;
            }
            #endregion
        }
        #endregion
    }
}

/*
 * refresh idea
// Were yourControl is the control or form that you are drawing on.
Application.Idle += EventHandler( yourControl.OnApplicationIdle );
void OnApplicationIdle (object sender, EventArgs e){     
// Forces the control to repaint itself. This will cause the OnPaint method to be called.    
// Another option is to directly inject the DirectX rendering code here     
// (Although the control and its child controls would not be redrawn).    
Invalidate();
}
 */